'''
项目名称：产业园区管理运营平台
文件名称：通知数据生成脚本
@Author: 王旭
@Contact: 1643959780@qq.com
@Created: 2025/06/29
@Version: V1.2

@Description:
本脚本为产业园区管理运营平台生成消息通知相关的模拟数据。
V1.2 版本更新：
- 统一使用"target_groups"和"specific_users"格式构建目标受众
- 消息广播状态简化为"待处理"和"已发布"两种状态
- 消息类型直接使用中文存储
- 优化消息回执的生成逻辑

V1.1 版本更新：
- 消息类型扩展为8种，与最新的系统设计保持一致。
- 为每种消息类型创建了专门的生成函数，逻辑更清晰。
- 对每种通知的发送目标进行了精确定义，使其更符合真实业务场景。
- 增加了每种类型通知的生成数量，便于前端进行充分的测试和展示。

依赖于 `init_personnel.py` 和 `init_finance.py` 生成的基础数据。
'''

import os
import sys
import django
import random
import datetime
from faker import Faker
from django.utils import timezone
from django.db import transaction

# --- Start: 动态添加项目根目录到 sys.path ---
current_script_path = os.path.abspath(__file__)
script_dir = os.path.dirname(current_script_path)
project_root = os.path.dirname(script_dir)
sys.path.append(project_root)
# --- End: 动态添加项目根目录到 sys.path ---

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'smartpark.settings')
django.setup()

from users.models import User, Company, Visitor, CompanyEmployeeProfile, ParkEmployeeProfile
from notification.models import Message, MessageBroadcast, MessageReceipt
from services.models import Contract  # 引入合同模型

# 初始化Faker
fake = Faker('zh_CN')

# 定义消息类型（直接使用中文）
MESSAGE_TYPES = [
    '园区公告',
    '新闻资讯',
    '审批提醒',
    '业务提醒',
    '合同提醒',
    '缴费提醒',
    '活动推广',
    '系统通知',
]

# 消息广播状态
BROADCAST_STATUS = {
    'DRAFT': '待处理',
    'PUBLISHED': '已发布'
}

def clear_old_notification_data():
    """以正确的顺序清除旧的通知数据，避免外键约束问题。"""
    print("--- 正在清除旧的通知数据... ---")
    MessageReceipt.objects.all().delete()
    MessageBroadcast.objects.all().delete()
    Message.objects.all().delete()
    print("旧的通知、广播及回执数据已清除。")

# --- 消息类型生成函数 ---

def create_announcements(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[0]} ---")
    for _ in range(num):
        title_template = random.choice([
            "关于园区{area}区域停水维护的紧急通知",
            "关于'五一'劳动节放假安排的公告",
            "园区消防安全演练通知",
            "关于调整班车{line}号线发车时间的公告",
        ])
        msg = Message.objects.create(
            title=title_template.format(area=random.choice(['A栋', 'B栋', '公共区域']), line=random.randint(1, 3)),
            content=fake.text(max_nb_chars=200),
            message_type=MESSAGE_TYPES[0],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(days=random.randint(1, 30)),
            valid_from=timezone.now(),
            valid_until=timezone.now() + datetime.timedelta(days=10)
        )
        broadcast_to(message=msg, target_groups=["企业员工", "物业员工"], specific_users=[])

def create_news(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[1]} ---")
    companies = list(Company.objects.all())
    if not companies: return
    for _ in range(num):
        title_template = random.choice([
            "热烈祝贺我园企业'{company_name}'荣获国家高新技术企业认证",
            "园区新闻速递：{date}日重要事件回顾",
            "聚焦产业动态：人工智能行业最新发展趋势分析",
            "政策解读：关于小微企业税收优惠的最新通知",
        ])
        msg = Message.objects.create(
            title=title_template.format(company_name=random.choice(companies).company_name, date=fake.date()),
            content=fake.paragraph(nb_sentences=5),
            message_type=MESSAGE_TYPES[1],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(days=random.randint(1, 30)),
            valid_from=timezone.now(),
            valid_until=timezone.now() + datetime.timedelta(days=365)
        )
        broadcast_to(message=msg, target_groups=["企业员工"], specific_users=[])

def create_approval_reminders(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[2]} ---")
    users_with_companies = list(CompanyEmployeeProfile.objects.select_related('user').all())
    if not users_with_companies: return

    for _ in range(num):
        applicant_profile = random.choice(users_with_companies)
        item = random.choice(['访客邀请', '装修申请', '入驻申请'])
        status = random.choice(['已通过', '已驳回'])
        title = f"【审批{status}】您提交的'{item}'已处理"
        content = f"尊敬的 {applicant_profile.name}，您好！您于 {fake.past_datetime(start_date='-30d').strftime('%Y-%m-%d')} 提交的 {item} 申请，经管理员审核，现已处理完毕。处理结果：{status}。请登录系统查看详情。"
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[2],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(minutes=random.randint(1, 60)),
            valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=7)
        )
        broadcast_to(message=msg, target_groups=[], specific_users=[applicant_profile.user.user_id])

def create_business_reminders(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[3]} ---")
    users = list(User.objects.all())
    if not users: return
    
    for _ in range(num):
        user = random.choice(users)
        service = random.choice(['报修服务', '送水订单', '保洁预约'])
        status = random.choice(['已派单', '正在处理中', '已完成'])
        title = f"【进度更新】您的'{service}'状态已更新为'{status}'"
        content = f"您好，您申请的 {service}（单号：{random.randint(10000, 99999)}）已有新进展，当前状态为：{status}。感谢您的耐心等待。"
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[3],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(minutes=random.randint(1, 120)),
            valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=3)
        )
        broadcast_to(message=msg, target_groups=["企业员工", "物业员工"], specific_users=[user.user_id])

def create_contract_reminders(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[4]} ---")
    contracts = list(Contract.objects.select_related('company', 'user').all())
    if not contracts: return

    for i in range(min(num, len(contracts))):
        contract = contracts[i]
        remind_type = random.choice(['待签署', '即将到期', '已到期'])
        
        specific_users = []
        
        # 更加精确地指定合同通知接收人：仅企业法人或合同签署人
        if contract.company:
            # 只找该公司的法人代表，而不是所有员工
            company_legal_reps = CompanyEmployeeProfile.objects.filter(
                company=contract.company,
                is_legal_representative=True  # 只选择法人代表
            )
            if company_legal_reps.exists():
                specific_users = [rep.user.user_id for rep in company_legal_reps]
            else:
                # 如果没找到法人代表，退而求其次找部门经理
                company_managers = CompanyEmployeeProfile.objects.filter(
                    company=contract.company,
                    is_department_manager=True  # 使用is_department_manager替代is_admin
                )
                if company_managers.exists():
                    specific_users = [manager.user.user_id for manager in company_managers][:1]  # 只取一个管理员
        
        # 如果是个人合同
        elif contract.user:
            specific_users.append(contract.user.user_id)
        
        # 如果没有找到任何接收者，跳过这个合同提醒
        if not specific_users:
            continue
            
        title = f"【合同提醒】合同'{contract.contract_number}'状态更新：{remind_type}"
        content = f"合同 {contract.contract_name}（编号：{contract.contract_number}）当前状态为 {remind_type}，请您关注并及时处理。到期日：{contract.end_date.strftime('%Y-%m-%d')}。"
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[4],
            sender_user=random.choice(admins),
            publish_time=timezone.now(), valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=30)
        )
        
        # 不使用广泛的target_groups，只发送给特定用户
        broadcast_to(message=msg, target_groups=[], specific_users=specific_users)

def create_payment_reminders(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[5]} ---")
    companies = list(Company.objects.all())
    if not companies: return

    for _ in range(num):
        company = random.choice(companies)
        month = fake.month_name()
        fee_type = random.choice(['物业费', '租金', '水电费'])
        title = f"【缴费提醒】{company.company_name} - {month}{fee_type}账单"
        content = f"尊敬的 {company.company_name}，您好！{month}{fee_type}账单已生成，金额为 {random.randint(1000, 50000)} 元，请于月底前完成支付，避免影响您的正常使用。"
        
        # 获取公司员工用户ID
        company_user_ids = []
        company_employees = CompanyEmployeeProfile.objects.filter(company=company)
        if company_employees.exists():
            company_user_ids = [emp.user.user_id for emp in company_employees[:5]]  # 最多取5个
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[5],
            sender_user=random.choice(admins),
            publish_time=timezone.now(), valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=15)
        )
        broadcast_to(message=msg, target_groups=["企业员工"], specific_users=company_user_ids)

def create_events(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[6]} ---")
    for _ in range(num):
        event = random.choice(['线上直播分享会', '线下招聘会', '创业者咖啡沙龙', '免费法律咨询活动'])
        title = f"【活动推广】邀您参加'{event}'"
        content = f"诚邀您参加将于 {fake.future_datetime(end_date='+60d').strftime('%Y-%m-%d')} 举办的 {event}。精彩不容错过，期待您的光临！"
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[6],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(days=random.randint(1, 10)),
            valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=60)
        )
        broadcast_to(message=msg, target_groups=["企业员工"], specific_users=[])

def create_system_notifications(admins, num=5):
    print(f"\n--- 正在生成 {num} 条 {MESSAGE_TYPES[7]} ---")
    for _ in range(num):
        subject = random.choice(['安全策略更新', '服务器维护', '隐私条款变更', '版本升级'])
        title = f"【系统通知】关于平台{subject}的通知"
        content = f"为了提供更优质的服务，平台将于近期进行{subject}。给您带来的不便，敬请谅解。"
        
        msg = Message.objects.create(
            title=title, content=content, message_type=MESSAGE_TYPES[7],
            sender_user=random.choice(admins),
            publish_time=timezone.now() - datetime.timedelta(days=random.randint(1, 20)),
            valid_from=timezone.now(), valid_until=timezone.now() + datetime.timedelta(days=5)
        )
        broadcast_to(message=msg, target_groups=["企业员工", "物业员工"], specific_users=[])

# 添加草稿消息的函数
def create_draft_messages(admins, num=5):
    print(f"\n--- 正在生成 {num} 条草稿消息 ---")
    for _ in range(num):
        message_type = random.choice(MESSAGE_TYPES)
        title = f"【草稿】{message_type}草稿 - {fake.sentence(nb_words=6)}"
        content = fake.paragraph(nb_sentences=3)
        
        # 草稿消息没有发布时间
        msg = Message.objects.create(
            title=title, 
            content=content, 
            message_type=message_type,
            sender_user=random.choice(admins),
            publish_time=None,  # 草稿消息发布时间为空
            valid_from=timezone.now(), 
            valid_until=timezone.now() + datetime.timedelta(days=30)
        )
        
        # 创建一个待处理状态的广播
        target_criteria = {
            'target_groups': ["企业员工"] if random.random() > 0.5 else ["企业员工", "物业员工"],
            'specific_users': []
        }
        
        broadcast = MessageBroadcast.objects.create(
            message=msg, 
            target_criteria=target_criteria, 
            status=BROADCAST_STATUS['DRAFT'],  # 待处理状态
            processing_log='草稿消息，等待发布'
        )
        print(f" -> 创建草稿消息: '{title[:25]}...'")


@transaction.atomic
def create_all_notification_data():
    """创建所有通知相关的模拟数据"""
    print("--- 开始创建消息通知数据 ---")
    
    try:
        admins = list(User.objects.filter(parkemployeeprofile__employee_type='管理员'))
        if not admins:
            print("警告：未找到管理员用户，无法指定发送者。请先运行 init_personnel.py。")
            return
        
        # 创建草稿消息
        create_draft_messages(admins)
        
        # 创建已发布的消息
        create_announcements(admins)
        create_news(admins)
        create_approval_reminders(admins)
        create_business_reminders(admins)
        create_contract_reminders(admins)
        create_payment_reminders(admins)
        create_events(admins)
        create_system_notifications(admins)

        print("\n\n消息通知数据生成完成！")
        print_statistics()
        
    except Exception as e:
        print(f"\n!!! 数据生成过程中发生错误，事务将回滚 !!!")
        print(f"错误详情: {e}")
        import traceback
        traceback.print_exc()

def broadcast_to(message: Message, target_groups: list = None, specific_users: list = None):
    """
    按照新的格式创建广播记录和回执
    """
    if target_groups is None:
        target_groups = []
    if specific_users is None:
        specific_users = []
        
    target_criteria = {
        'target_groups': target_groups,
        'specific_users': specific_users
    }
    
    print(f"\n正在广播消息: '{message.title[:25]}...' -> 目标: {target_criteria}")
    
    broadcast = MessageBroadcast.objects.create(
        message=message, 
        target_criteria=target_criteria, 
        status=BROADCAST_STATUS['PUBLISHED'],  # 已发布状态
        completed_at=timezone.now()
    )

    receipts_to_create = []
    user_ids = set()
    
    # 处理目标群体
    if "企业员工" in target_groups:
        company_employees = CompanyEmployeeProfile.objects.all()
        if company_employees.exists():
            user_ids.update(p.user_id for p in company_employees)
            
    if "物业员工" in target_groups:
        park_employees = ParkEmployeeProfile.objects.all()
        if park_employees.exists():
            user_ids.update(p.user_id for p in park_employees)
    
    # 添加特定用户
    if specific_users:
        user_ids.update(specific_users)

    # 创建回执
    for uid in user_ids:
        receipts_to_create.append(MessageReceipt(
            message=message, 
            broadcast=broadcast, 
            user_id=uid,
            read_status=False
        ))
        
    if not receipts_to_create:
        print(" -> 警告：未找到符合条件的目标接收者。")
        return

    # 批量创建回执
    MessageReceipt.objects.bulk_create(receipts_to_create, ignore_conflicts=True)
    
    # 模拟部分已读 - 针对不同类型的消息调整已读率
    receipts_just_created = MessageReceipt.objects.filter(broadcast=broadcast)
    if receipts_just_created.exists():
        # 根据消息类型调整已读率：
        # - 合同和审批提醒：90%~100%已读率（重要通知）
        # - 其他类型消息：20%~80%已读率（普通通知）
        if message.message_type in [MESSAGE_TYPES[2], MESSAGE_TYPES[4]]:  # 审批提醒、合同提醒
            read_ratio = random.uniform(0.9, 1.0)  # 90%-100%的已读率
        else:
            read_ratio = random.uniform(0.2, 0.8)  # 20%-80%的已读率
            
        # 特定用户直接发送的消息，几乎都会被读取
        if not target_groups and specific_users:
            read_ratio = random.uniform(0.95, 1.0)  # 95%-100%的已读率
            
        read_count = min(receipts_just_created.count(), int(receipts_just_created.count() * read_ratio))
        if read_count > 0:
            read_receipts = random.sample(list(receipts_just_created), k=read_count)
            
            for receipt in read_receipts:
                receipt.read_status = True
                # 合同和审批提醒通常会更快被阅读
                if message.message_type in [MESSAGE_TYPES[2], MESSAGE_TYPES[4]]:
                    days_delay = random.randint(0, 1)  # 0-1天内读取
                else:
                    days_delay = random.randint(0, 5)  # 0-5天内读取
                    
                # 使用publish_time或创建时间计算已读时间
                base_time = message.publish_time if message.publish_time else message.created_at
                read_time = base_time + datetime.timedelta(days=days_delay, 
                                                         hours=random.randint(0, 23), 
                                                         minutes=random.randint(0, 59))
                receipt.read_time = read_time
            
            MessageReceipt.objects.bulk_update(read_receipts, ['read_status', 'read_time'])

    print(f" -> 成功生成 {receipts_just_created.count()} 条个人回执, 其中 {len(read_receipts) if 'read_receipts' in locals() else 0} 条被模拟为已读。")


def print_statistics():
    """打印数据统计信息"""
    print("\n=== 消息通知数据统计 ===")
    
    message_count = Message.objects.count()
    broadcast_count = MessageBroadcast.objects.count()
    receipt_count = MessageReceipt.objects.count()
    read_receipt_count = MessageReceipt.objects.filter(read_status=True).count()
    draft_count = MessageBroadcast.objects.filter(status=BROADCAST_STATUS['DRAFT']).count()
    published_count = MessageBroadcast.objects.filter(status=BROADCAST_STATUS['PUBLISHED']).count()
    
    print(f"消息内容总数: {message_count}条")
    print(f"广播事件总数: {broadcast_count}次")
    print(f"  - 待处理消息: {draft_count}条")
    print(f"  - 已发布消息: {published_count}条")
    print(f"个人回执总数: {receipt_count}条")
    if receipt_count > 0:
        read_percentage = (read_receipt_count / receipt_count) * 100
        print(f"  - 已读回执: {read_receipt_count}条 (平均已读率: {read_percentage:.2f}%)")


if __name__ == "__main__":
    clear_old_notification_data()
    create_all_notification_data() 